/**
 * @file transcode.h
 * @author Yu Zhong (lx1zhong@qq.com)
 * @brief Header file for ADT-FSE algorithm
 * @date 2022-08-25
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#ifndef _Transcode_H
#define _Transcode_H
#include "sz.h"
#include "mem.h"

#ifdef __cplusplus
extern "C" {
#endif


#ifdef WINDOWS
int32_t BUILDIN_CLZ_EX(uint32_t val);
#else
#define BUILDIN_CLZ_EX(val)  __builtin_clz(val)
#endif

/**
 *  dict = {
        0: [0,0], 1:[1,0], 2:[2,0], 3:[3,0],
        4: [4,0], 5:[5,0], 6:[6,0], 7:[7,0],
        8: [8,0], 9:[9,0], 10:[10,0], 11:[11,0],
        12: [12,0], 13:[13,0], 14:[14,0], 15:[15,0],
        16: [16,1], 18:[17,1], 20:[18,1], 22:[19,1],
        24: [20,2], 28:[21,2], 32:[22,3], 40:[23,3],
        48: [24,4], 64:[25,6], 128:[26,7], 256:[27,8],
        512: [28,9], 1024:[29,10], 2048:[30,11], 4096:[31,12],
        8192: [32,13], 16384:[33,14], 
        -8192: [35,13], -16384:[34,14], 
        -512: [39,9], -1024:[38,10], -2048:[37,11], -4096:[36,12],
        -48: [43,4], -64:[42,6], -128:[41,7], -256:[40,8],
        -24: [47,2], -28:[46,2], -32:[45,3], -40:[44,3],
        -16: [51,1], -18:[50,1], -20:[49,1], -22:[48,1],
        -12: [55,0], -13:[54,0], -14:[53,0], -15:[52,0],
        -8: [59,0], -9:[58,0], -10:[57,0], -11:[56,0],
        -4: [63,0], -5:[62,0], -6:[61,0], -7:[60,0],
        -1:[66,0], -2:[65,0], -3:[64,0],
        #-16384:[67,0]
    }
 * 
 */

MEM_STATIC int Int2code(int factor)
{
    static const uint8_t Ft_Code[64] = {  0,  1,  2,  3,  4,  5,  6,  7,
                                          8,  9, 10, 11, 12, 13, 14, 15,
                                         16, 16, 17, 17, 18, 18, 19, 19,
                                         20, 20, 20, 20, 21, 21, 21, 21,
                                         22, 22, 22, 22, 22, 22, 22, 22,
                                         23, 23, 23, 23, 23, 23, 23, 23,
                                         24, 24, 24, 24, 24, 24, 24, 24,
                                         24, 24, 24, 24, 24, 24, 24, 24 };
    if (factor >= 0)
        return (factor > 63) ? 50 - BUILDIN_CLZ_EX(factor) : Ft_Code[factor];
    else {
        factor = -factor;
        return (factor > 63) ? 17 + BUILDIN_CLZ_EX(factor) : 67 - Ft_Code[factor];
    }
}

/**
 * reverse_dict = {
            0: [0,0], 1:[1,0], 2:[2,0], 3:[3,0],
            4: [4,0], 5:[5,0], 6:[6,0], 7:[7,0],
            8: [8,0], 9:[9,0], 10:[10,0], 11:[11,0],
            12: [12,0], 13:[13,0], 14:[14,0], 15:[15,0],
            16: [16,1], 17:[18,1], 18:[20,1], 19:[22,1],
            20: [24,2], 21:[28,2], 22:[32,3], 23:[40,3],
            24: [48,4], 25:[64,6], 26:[128,7], 27:[256,8],
            28: [512,9], 29:[1024,10], 30:[2048,11], 31:[4096,12],
            32: [8192,13], 33:[16384,14],
            35:[-8192,13], 34:[-16384,14],
            39:[-512,9], 38:[-1024,10], 37:[-2048,11], 36:[-4096,12],
            43:[-48,4], 42:[-64,6], 41:[-128,7], 40:[-256,8],
            47:[-24,2], 46:[-28,2], 45:[-32,3], 44:[-40,3],
            51:[-16,1], 50:[-18,1], 49:[-20,1], 48:[-22,1],
            55:[-12,0], 54:[-13,0], 53:[-14,0], 52:[-15,0],
            59:[-8,0], 58:[-9,0], 57:[-10,0], 56:[-11,0],
            63:[-4,0], 62:[-5,0], 61:[-6,0], 60:[-7,0],
            66:[-1,0], 65:[-2,0], 64:[-3,0],
            #67:[-16384,0]
        }
 * 
 */
static const int code2int[67][2] = { {0,0},{1,0},{2,0},{3,0},
                                     {4,0},{5,0},{6,0},{7,0},
                                     {8,0},{9,0},{10,0},{11,0},
                                     {12,0},{13,0},{14,0},{15,0},
                                     {16,1},{18,1},{20,1},{22,1},
                                     {24,2},{28,2},{32,3},{40,3},
                                     {48,4},{64,6},{128,7},{256,8},
                                     {512,9},{1024,10},{2048,11},{4096,12},
                                     {8192,13},{16384,14},
                                     {-16384,14}, {-8192,13},
                                     {-4096,12},{-2048,11},{-1024,10},{-512,9},
                                     {-256,8},{-128,7},{-64,6},{-48,4},
                                     {-40,3},{-32,3},{-28,2},{-24,2},
                                     {-22,1},{-20,1},{-18,1},{-16,1},
                                     {-15,0},{-14,0},{-13,0},{-12,0},
                                     {-11,0},{-10,0},{-9,0},{-8,0},
                                     {-7,0},{-6,0},{-5,0},{-4,0},
                                     {-3,0},{-2,0},{-1,0} };

void encode_with_fse(int *type, size_t dataSeriesLength, unsigned int intervals, 
                    unsigned char **FseCode, size_t *FseCode_size, 
                    unsigned char **transCodeBits, size_t *transCodeBits_size);
void decode_with_fse(int *type, size_t dataSeriesLength, unsigned int intervals, 
                    unsigned char *FseCode, size_t FseCode_size, 
                    unsigned char *transCodeBits, size_t transCodeBits_size);

#ifdef __cplusplus
}
#endif

#endif